package com.yangl.study.beans.factory;

import com.yangl.study.beans.BeanDefinition;
import com.yangl.study.beans.BeanPostProcessor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author yanglei
 * @date 2021-12-02 21:33
 */
public abstract class AbstractBeanFactory implements BeanFactory {

    /**
     * beanDefinition 缓存
     */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

    private final List<String> beanDefinitionNames = new ArrayList<String>();

    private List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();

    @Override
    public Object getBean(String name) throws Exception {
        // bean 需要先注册到 beanDefinitionMap 中
        BeanDefinition beanDefinition = beanDefinitionMap.get(name);
        if (beanDefinition == null) {
            throw new IllegalArgumentException("No bean named " + name + " is defined");
        }
        Object bean = beanDefinition.getBean();
        if (bean == null) {
            // 如果 beanDefinition 中的 bean 为空 , 则根据 beanDefinition 创建 bean
            bean = doCreateBean(beanDefinition);
            bean = initializeBean(bean, name);
            beanDefinition.setBean(bean);
        }
        return bean;
    }

    protected Object initializeBean(Object bean, String name) throws Exception {
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            bean = beanPostProcessor.postProcessBeforeInitialization(bean, name);
        }

        // TODO:call initialize method
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            bean = beanPostProcessor.postProcessAfterInitialization(bean, name);
        }
        return bean;
    }

    protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
        return beanDefinition.getBeanClass().newInstance();
    }

    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
        // 缓存 beanDefinition 到 Map 解决循环依赖问题
        beanDefinitionMap.put(name, beanDefinition);
        // 保存 beanName
        beanDefinitionNames.add(name);
    }

    public void preInstantiateSingletons() throws Exception {
        for (String beanName : this.beanDefinitionNames) {
            getBean(beanName);
        }
    }

    /**
     * 根据 BeanDefinition 创建bea
     *
     * @param beanDefinition bean的定义类
     * @return 返回创建的bean
     * @throws Exception 异常
     */
    protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
        System.out.println("doCreateBean ----->" + beanDefinition.getBeanClassName());
        Object bean = createBeanInstance(beanDefinition);
        beanDefinition.setBean(bean);
        applyPropertyValues(bean, beanDefinition);
        return bean;
    }

    protected void applyPropertyValues(Object bean, BeanDefinition beanDefinition) throws Exception {

    }

    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) throws Exception {
        this.beanPostProcessors.add(beanPostProcessor);
    }

    public List getBeansForType(Class type) throws Exception {
        List beans = new ArrayList<Object>();
        for (String beanDefinitionName : beanDefinitionNames) {
            if (type.isAssignableFrom(beanDefinitionMap.get(beanDefinitionName).getBeanClass())) {
                beans.add(getBean(beanDefinitionName));
            }
        }
        return beans;
    }

    static class A {
    }

    static class B extends A {
    }

    public static class Test1 {
        public static void main(String[] args) {

            A a = new A();
            B b = new B();
            A ba = new B();
            System.out.println("1-------------");
            System.out.println(A.class.isAssignableFrom(a.getClass()));     //true
            System.out.println(B.class.isAssignableFrom(b.getClass()));     //true
            System.out.println(A.class.isAssignableFrom(b.getClass()));     //true
            System.out.println(B.class.isAssignableFrom(a.getClass()));     //false
            System.out.println(A.class.isAssignableFrom(ba.getClass()));    //true
            System.out.println(B.class.isAssignableFrom(ba.getClass()));    //true
            System.out.println("2-------------");
            System.out.println(a.getClass().isAssignableFrom(A.class));     //true
            System.out.println(b.getClass().isAssignableFrom(B.class));     //true
            System.out.println(a.getClass().isAssignableFrom(B.class));     //true
            System.out.println(b.getClass().isAssignableFrom(A.class));     //false
            System.out.println(ba.getClass().isAssignableFrom(A.class));    //false
            System.out.println(ba.getClass().isAssignableFrom(B.class));    //true
            System.out.println("3-------------");
            System.out.println(Object.class.isAssignableFrom(b.getClass()));        //true
            System.out.println(Object.class.isAssignableFrom("abc".getClass()));    //true
            System.out.println("4-------------");
            System.out.println("a".getClass().isAssignableFrom(Object.class));      //false
            System.out.println("abc".getClass().isAssignableFrom(Object.class));    //false
        }
    }
}
